package com.leo.utils;

import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * bitmap 工具类
 * 
 * created by leo 2016/04/26
 */
public class BitmapUtil {

    private BitmapUtil() {
    }

    /**
     * ALPHA_8:数字为8，图形参数应该由一个字节来表示,应该是一种8位的位图 ARGB_4444:4+4+4+4=16，图形的参数应该由两个字节来表示,应该是一种16位的位图. ARGB_8888:8+8+8+8=32，图形的参数应该由四个字节来表示,应该是一种32位的位图. RGB_565:5+6+5=16，图形的参数应该由两个字节来表示,应该是一种16位的位图.
     *
     * ALPHA_8，ARGB_4444，ARGB_8888都是透明的位图，也就是所字母A代表透明。 ARGB_4444:意味着有四个参数,即A,R,G,B,每一个参数由4bit表示. ARGB_8888:意味着有四个参数,即A,R,G,B,每一个参数由8bit来表示. RGB_565:意味着有三个参数,R,G,B,三个参数分别占5bit,6bit,5bit.
     *
     *
     * BitmapFactory.Options.inPurgeable;
     *
     * 如果 inPurgeable 设为True的话表示使用BitmapFactory创建的Bitmap 用于存储Pixel的内存空间在系统内存不足时可以被回收， 在应用需要再次访问Bitmap的Pixel时（如绘制Bitmap或是调用getPixel）， 系统会再次调用BitmapFactory decoder重新生成Bitmap的Pixel数组。
     * 为了能够重新解码图像，bitmap要能够访问存储Bitmap的原始数据。
     *
     * 在inPurgeable为false时表示创建的Bitmap的Pixel内存空间不能被回收， 这样BitmapFactory在不停decodeByteArray创建新的Bitmap对象， 不同设备的内存不同，因此能够同时创建的Bitmap个数可能有所不同， 200个bitmap足以使大部分的设备重新OutOfMemory错误。 当isPurgable设为true时，系统中内存不足时，
     * 可以回收部分Bitmap占据的内存空间，这时一般不会出现OutOfMemory 错误。
     */

    /**
     * @param file
     * @param size 最小宽度
     * @return
     */
    public static Bitmap decodeWithSize(String file, int size) {
        Options opts = new Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(file, opts);
        int nw = opts.outWidth;
        int nh = opts.outHeight;
        opts.inJustDecodeBounds = false;
        opts.outHeight = size;
        opts.outWidth = nw * size / nh;
        return BitmapFactory.decodeFile(file, opts);
    }

    /**
     * 获得圆角图片的方法
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {

        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

    /**
     * 将Drawable转化为Bitmap
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height,
                drawable.getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 : Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, width, height);
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * 放大缩小图片
     */
    public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Matrix matrix = new Matrix();
        float scaleWidht = ((float) w / width);
        float scaleHeight = ((float) h / height);
        matrix.postScale(scaleWidht, scaleHeight);
        Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
        return newbmp;
    }

    /**
     * 图片透明度处理
     *
     * @param sourceImg 原始图片
     * @param number    透明度
     * @return
     */
    public static Bitmap setAlpha(Bitmap sourceImg, int number) {
        int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()];
        sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0, sourceImg.getWidth(), sourceImg.getHeight());// 获得图片的ARGB值
        number = number * 255 / 100;
        for (int i = 0; i < argb.length; i++) {
            // argb = (number << 24) | (argb & 0x00FFFFFF);// 修改最高2位的值
        }
        sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(), sourceImg.getHeight(), Config.ARGB_8888);
        return sourceImg;
    }


    public static Bitmap drawbitmap(int color, int w, int h) {
        Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(color);
        return bitmap;
    }

    public static Bitmap drawbitmap(int color, int w, int h, float density) {
        Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        bitmap.setDensity((int) density);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(color);
        return bitmap;
    }

    /**
     * 压缩图片大小
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(CompressFormat.JPEG, 100, baos);// 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();// 重置baos即清空baos
            image.compress(CompressFormat.JPEG, options, baos);// 这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;// 每次都减少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
        return bitmap;
    }


    /**
     * 压缩图片大小
     *
     * @param filePath
     * @return
     */
    public static int compressImageTosize(String filePath) {
        Bitmap bitmap = BitmapFactory.decodeFile(filePath);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(CompressFormat.JPEG, 80, baos);//
        return baos.size();
    }

    public static boolean saveBitmap(String path, Bitmap bitmap) {
        File f = new File(path);
        try {
            bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(f));
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }


    //   <=================================================图片压缩部分==================================>
    public static final int MAX_PIC_WIDTH = 1200;
    public static final int MAX_PIC_HEIGHT = 1200;


    final static int MAX_WIDTH = 640;
    final static int MAX_HEIGHT = 960;
    final static int MAX_PIXEL = 450 * 10000;

    public static Bitmap decodeBitmapFromResource(String filePath) {
        return decodeBitmapFromResource(filePath, MAX_PIC_WIDTH, MAX_PIC_HEIGHT);
    }

    /**
     * 把bitmap压缩，第一个参数如果是100，表示不压缩， 在实验的过程中设置为60，图片都不会失真。 具体情况待验证
     *
     * @param
     * @return
     */
    public static byte[] compressBmp(Bitmap bm) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            if (bm == null)
                return null;
            int options = 80;
            bm.compress(CompressFormat.JPEG, options, baos);
            while (baos.toByteArray().length / 1024 > 150 && options >= 50) {
                // 当压缩完图片还是大于150K时，继续压缩
                baos.reset();
                bm.compress(CompressFormat.JPEG, options, baos);
                options -= 10;
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                baos.close();
            } catch (IOException e) {
                // do nothing
            }
        }
        return null;
    }

    // 在google推荐的算法基础上，再通过限制最大的高宽来缩放图片，
    // 原因：google的推荐算法inSampleSize是2的N次方，英文是:the power of 2,会导致想缩放1/7也只能使用1/4的缩放
    private static Bitmap decodeBitmapFromResource(String filePath, int reqWidth, int reqHeight) {
        // 首先不加载图片,仅获取图片尺寸
        final Options options = new Options();
        options.inJustDecodeBounds = true;
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeFile(filePath, options);
        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4，
        // 使用google推荐的算法:http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // 如果按压缩比例，还大于最大的宽高，则强制缩放
        // or example, downsampling from 2448x3264 image to 1200x1200, it will become 900x1200
        final int newWidth = options.outWidth / options.inSampleSize;
        final int newHeight = options.outHeight / options.inSampleSize;
        if (newWidth > reqWidth || newHeight > reqHeight) {
            if (newWidth * reqHeight > newHeight * reqWidth) {
                // prefer width, as the width ratio is larger
                options.inTargetDensity = reqWidth;
                options.inDensity = newWidth;
            } else {
                // prefer height
                options.inTargetDensity = reqHeight;
                options.inDensity = newHeight;
            }
        }

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filePath, options);
    }

    // google推荐的算法，使用inSampleSize来缩放图片
    public static Bitmap decodeBitmapByInSampleSize(String filePath) {
        return decodeBitmapByInSampleSize(filePath, MAX_PIC_WIDTH, MAX_PIC_HEIGHT);
    }

    private static Bitmap decodeBitmapByInSampleSize(String filePath, int reqWidth, int reqHeight) {
        // 首先不加载图片,仅获取图片尺寸
        final Options options = new Options();
        options.inJustDecodeBounds = true;
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeFile(filePath, options);
        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filePath, options);
    }

    private static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int dstWidth, int dstHeight,
                                                          Config config) {

        // 首先不加载图片,仅获取图片尺寸
        final Options options = new Options();

        options.inPreferredConfig = config;

        // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
        options.inJustDecodeBounds = true;
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeResource(res, resId, options);

        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
        options.inSampleSize = calculateInSampleSize(options, dstWidth, dstHeight);

        // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了
        options.inJustDecodeBounds = false;
        // 利用计算的比例值获取压缩后的图片对象
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int dstWidth, int dstHeight) {

        // Config.RGB_565一个像素占2字节，无透明度， ARGB_8888占4个字节
        return decodeSampledBitmapFromResource(res, resId, dstWidth, dstHeight, Config.RGB_565);
    }

    public static Bitmap decodeSampledBitmapFromByteArray(byte[] bytes, int dstWidth, int dstHeight) {

        // Config.RGB_565一个像素占2字节，无透明度， ARGB_8888占4个字节
        return decodeSampledBitmapFromByteArray(bytes, dstWidth, dstHeight, Config.RGB_565);
    }

    public static Bitmap decodeSampledBitmapFromByteArray(byte[] bytes, int dstWidth, int dstHeight, Config config) {

        // 首先不加载图片,仅获取图片尺寸
        final Options options = new Options();

        options.inPreferredConfig = config;

        // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息
        options.inJustDecodeBounds = true;
        // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);

        // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4
        options.inSampleSize = calculateInSampleSize(options, dstWidth, dstHeight);

        // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了
        options.inJustDecodeBounds = false;
        // 利用计算的比例值获取压缩后的图片对象
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    }

    /**|
     *    计算压缩比例
     * @param options
     * @param dstWidth
     * @param dstHeight
     * @return
     */
    public static int calculateInSampleSize(Options options, int dstWidth, int dstHeight) {
        // 保存图片原宽高值
        final int height = options.outHeight;
        final int width = options.outWidth;
        // 初始化压缩比例为1
        int inSampleSize = 1;

        // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统
        if (height > dstHeight || width > dstWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // 压缩比例值每次循环两倍增加,
            // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止
            while ((halfHeight / inSampleSize) >= dstHeight && (halfWidth / inSampleSize) >= dstWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }


    /**
     * Get the value of the data column for this Uri. This is useful for MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     *   获得图片的options
     * @param path
     * @return
     */
    public static Options getPhotoHeiWidOptions(String path) {
        Options options = new Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        return options;
    }

    /**
     *  通过url 返回 bitmap
     * @param url
     * @return
     */
    public static Bitmap returnBitmap(String url) {
        URL fileUrl = null;
        Bitmap bitmap = null;

        try {
            fileUrl = new URL(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            HttpURLConnection conn = (HttpURLConnection) fileUrl
                    .openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;

    }
}
